#include "LightHelper.fx"


//=================================================================================================
// Postion and material constant buffer
//=================================================================================================
cbuffer cbPerObject
{
	float4x4 wMatrix;
	float4x4 vMatrix;
	float4x4 pMatrix;
	float4x4 rMatrix;
};


//=================================================================================================
// Light constant buffer
//=================================================================================================
cbuffer cbPerFrame
{
	DirectionLight gDirLight;
	float3         gEyePosW;
	Material       gMaterial;
};


//=================================================================================================
// Texture resource
//=================================================================================================
Texture2D gTexDiffuse;


//=================================================================================================
// Sampler state
//=================================================================================================
SamplerState samLinear
{
	AddressU = WRAP;
	AddressV = WRAP;
};


//=================================================================================================
// Input struct vertex shader
//=================================================================================================
struct VertexIn
{
	float4 PosL : POSITION;
	float3 NorL : NOR;
	float2 TexL : TEXCOORD;
};


//=================================================================================================
// Output struct after vertex shader
//=================================================================================================
struct VertexOut
{
	float4 PosH : SV_POSITION;
    float3 PosW : POSITION;
	float2 TexW : TEXCOORD;
    float3 NorW : NORMAL;
};


//=================================================================================================
// Vertex shader
//=================================================================================================
VertexOut VS(VertexIn vetxIn)
{
	VertexOut output = (VertexOut)0;
	
	// Transform to world space space.
	output.PosW = mul(vetxIn.PosL, wMatrix).xyz;
	output.NorW = mul(vetxIn.NorL, (float3x3)rMatrix);
	output.TexW = vetxIn.TexL;
	
	// Caculate the position.
	output.PosH = mul(vetxIn.PosL, wMatrix);
	output.PosH = mul(output.PosH, vMatrix);
	output.PosH = mul(output.PosH, pMatrix);
	return output;
}


//=================================================================================================
// Pixel shader
//================================================================================================= 
float4 PS(VertexOut pin) : SV_TARGET
{
	// Interpolating normal can unnormalize it, so normalize it.
	pin.NorW = normalize(pin.NorW);
	
	// Caculate light direction.
	float3 toEyeW = normalize(gEyePosW - pin.PosW);

	// Start with a sum of zero. 
	float4 ambient  = float4(0.0f, 0.0f, 0.0f, 0.0f);
	float4 diffuse  = float4(0.0f, 0.0f, 0.0f, 0.0f);
	float4 specular = float4(0.0f, 0.0f, 0.0f, 0.0f);

	// Sum the light contribution from each light source.
	float4 A, D, S;
	
	// Direction light.
	ComputeDL(gMaterial, gDirLight, pin.NorW, toEyeW, A, D, S);
	ambient  += A;  
	diffuse  += D;
	specular += S;

	// Final color. 
	float4 texColor = gTexDiffuse.Sample(samLinear, pin.TexW);
	float4 litColor = 0.5 * texColor * (1 + ambient + diffuse) + specular;

	// Common to take alpha from diffuse material.
	litColor.a = gMaterial.Diffuse.a;
    return litColor;
}


//=================================================================================================
// Technique shader
//=================================================================================================
technique11 LightingShaderTech
{
    pass P0
    {
        SetVertexShader(CompileShader(vs_5_0, VS()));
		SetGeometryShader(NULL);
        SetPixelShader(CompileShader(ps_5_0, PS()));
    }
}